package com.pivotal.cloud.security.password;

import com.pivotal.cloud.crypto.Digester;
import com.pivotal.cloud.crypto.codec.Hex;
import com.pivotal.cloud.crypto.codec.Utf8;
import com.pivotal.cloud.crypto.keygen.Base64StringKeyGenerator;
import com.pivotal.cloud.crypto.keygen.StringKeyGenerator;
import com.pivotal.cloud.crypto.utils.EncodingUtil;

import java.util.Base64;

/**
 * @className: MessageDigestPasswordEncoder
 * @projectName: PivotalCloud项目
 * @module: PivotalCloud项目-MessageDigestPasswordEncoder类，主要位于Security安全模块-MessageDigest模式密码加密模块
 * @content: MessageDigestPasswordEncoder-MessageDigest模式密码加密
 * @author: Powered by Marklin
 * @datetime: 2025-06-24 13:29
 * @version: 1.0.0
 * @copyright: Copyright © 2018-2025 PivotalCloud Systems Incorporated. All rights
 * reserved.
 */
public class MessageDigestPasswordEncoder implements PasswordEncoder {

	private static final String PREFIX = "{";

	private static final String SUFFIX = "}";

	private final StringKeyGenerator saltGenerator = new Base64StringKeyGenerator();

	private boolean encodeHashAsBase64;

	private final Digester digester;

	/**
	 * 实例化对象
	 */
	private static final PasswordEncoder INSTANCE = MessageDigestPasswordEncoder.newInstance();

	/**
	 * 获取实例
	 * @return 返回结果
	 */
	public static PasswordEncoder getInstance() {
		return INSTANCE;
	}

	/**
	 * 实例化对象
	 * @return 返回结果
	 */
	public static PasswordEncoder newInstance() {
		return new NoopPasswordEncoder();
	}

	public MessageDigestPasswordEncoder(String algorithm) {
		this.digester = new Digester(algorithm, 1);
	}

	public void setEncodeHashAsBase64(boolean encodeHashAsBase64) {
		this.encodeHashAsBase64 = encodeHashAsBase64;
	}

	/**
	 * 密码加密
	 * @param rawPassword 原始密码
	 * @return 返回结果
	 */
	@Override
	public String encode(CharSequence rawPassword) {
		String salt = PREFIX + this.saltGenerator.generateKey() + SUFFIX;
		return digest(salt, rawPassword);
	}

	private String digest(String salt, CharSequence rawPassword) {
		String saltedPassword = rawPassword + salt;
		byte[] digest = this.digester.digest(Utf8.encode(saltedPassword));
		String encoded = encode(digest);
		return salt + encoded;
	}

	private String encode(byte[] digest) {
		if (this.encodeHashAsBase64) {
			return Utf8.decode(Base64.getEncoder().encode(digest));
		}
		return new String(Hex.encode(digest));
	}

	/**
	 * 验证密码
	 * @param rawPassword 原始密码
	 * @param encodedPassword 加密密码
	 * @return 返回结果
	 */
	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		String salt = extractSalt(encodedPassword);
		String rawPasswordEncoded = digest(salt, rawPassword);
		return EncodingUtil.equals(encodedPassword.toString(), rawPasswordEncoded);
	}

	public void setIterations(int iterations) {
		this.digester.setIterations(iterations);
	}

	private String extractSalt(String prefixEncodedPassword) {
		int start = prefixEncodedPassword.indexOf(PREFIX);
		if (start != 0) {
			return "";
		}
		int end = prefixEncodedPassword.indexOf(SUFFIX, start);
		if (end < 0) {
			return "";
		}
		return prefixEncodedPassword.substring(start, end + 1);
	}

}
